import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:flustars/flustars.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'package:get/get.dart' hide Response; //用hide关键词隐藏掉你不用的那个包中的类  或者用as关键词将不用的那个包的类名更换  來解決依賴庫裡面重複依賴問題
import '../res/constant.dart';
import '../util/log_utils.dart';
import '../util/toast_utils.dart';
import 'base_entity.dart';
import 'error_handle.dart';
import 'http_config.dart';

typedef NetSuccessCallbackOrignal = Function(dynamic data);
typedef NetSuccessCallback<T> = Function(T data);
typedef NetSuccessListCallback<T> = Function(List<T> data);
typedef NetErrorCallback = Function(String code, String msg);

/// @weilu https://github.com/simplezhli
class DioUtils {
  factory DioUtils() => _singleton ?? DioUtils._();

  DioUtils._();

  static DioUtils? _singleton = DioUtils._();

  static DioUtils get instance => DioUtils();

  static late Dio _realDio;

  // 数据返回格式统一，统一处理异常
  Future<BaseEntity<T>> _request<T>(
    String method,
    String url, {
    BASE_URL? baseUrlType = BASE_URL.base,
    Object? data,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    Options? options,
  }) async {
    _realDio = httpConfig.dio;
    if (baseUrlType == BASE_URL.m) {
      _realDio = httpConfig.mDio;
    } else if (baseUrlType == BASE_URL.m2) {
      _realDio = httpConfig.m2Dio;
    }

    final Response<String> response = await _realDio.request<String>(
      url,
      data: data,
      queryParameters: queryParameters,
      options: _checkOptions(method, options),
      cancelToken: cancelToken,
    );
    try {
      final String data = response.data.toString();

      /// 集成测试无法使用 isolate https://github.com/flutter/flutter/issues/24703
      /// 使用compute条件：数据大于10KB（粗略使用10 * 1024）且当前不是集成测试（后面可能会根据Web环境进行调整）
      /// 主要目的减少不必要的性能开销
      final bool isCompute = !Constant.isDriverTest && data.length > 10 * 1024;
      debugPrint('isCompute:$isCompute');
      final Map<String, dynamic> map = isCompute ? await compute(parseData, data) : parseData(data);
      // if(map["data"] != null && map["data"]["code"] == 4) {
      //   Future.delayed(Duration.zero).then((value) => Get.offAll(() => LoginPageNew()));
      //   // BoostChannel.instance.sendEventToNative("native_CommonEvent", {"method": "login"});
      //   return BaseEntity<T>(ExceptionHandle.logout, map["data"]["message"] , null);
      // }
      MyLog.e("请求接口的回调--> $map");
      if (map["code"] == 0) {
        Map<String, dynamic> dataMap = map["data"];
        return BaseEntity<T>.fromJson(map["data"]);
      } else if (map["code"] == 4) {
        //说明token失效了
        SpUtil.remove(Constant.accessToken); //重新登录
        BoostChannel.instance.sendEventToNative("native_CommonEvent", {"method": "login"});
        // Get.offAll(LoginPage());
        return BaseEntity<T>(ExceptionHandle.token_error, 'Token is invalid', null);
      } else {
        return BaseEntity<T>(map["code"], map["message"], map["data"]);
      }
    } catch (e) {
      debugPrint(e.toString());
      return BaseEntity<T>(ExceptionHandle.parse_error, '数据解析错误！', null);
    }
  }

  Options _checkOptions(String method, Options? options) {
    options ??= Options();
    options.method = method;
    options.contentType = "application/json";
    return options;
  }

  // 数据返回原始格式
  Future _requestOriginal(
    String method,
    String url, {
    BASE_URL? baseUrlType = BASE_URL.base,
    Object? data,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    Options? options,
  }) async {
    _realDio = httpConfig.dio;
    if (baseUrlType == BASE_URL.m) {
      _realDio = httpConfig.mDio;
    } else if (baseUrlType == BASE_URL.m2) {
      _realDio = httpConfig.m2Dio;
    }
    final Response<String> response = await _realDio.request<String>(
      url,
      data: data,
      queryParameters: queryParameters,
      options: _checkOptions(method, options),
      cancelToken: cancelToken,
    );
    return response;
  }

  Future<dynamic> requestNetworkBackCallOriginal(
    Method method,
    String url, {
    BASE_URL? urlType,
    NetSuccessCallbackOrignal? onSuccess,
    NetErrorCallback? onError,
    Object? params,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    Options? options,
  }) {
    return _requestOriginal(
      method.value,
      url,
      baseUrlType: urlType,
      data: params,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
    ).then((value) {
      if (onSuccess != null) {
        onSuccess(value);
      }
    });
  }

  Future<dynamic> requestNetwork<T>(
    Method method,
    String url, {
    BASE_URL? urlType,
    NetSuccessCallback<T?>? onSuccess,
    NetErrorCallback? onError,
    Object? params,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    Options? options,
  }) {
    MyLog.d("--------1111111--data-----" + params.toString() + "options---options---" + options.toString());
    return _request<T>(
      method.value,
      url,
      baseUrlType: urlType,
      data: params,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
    ).then<void>((BaseEntity<T> result) {
      MyLog.e("$url 接口请求成功 -- code = ${result.code} ; message =${result.message} ; data = ${result.data}");

      if (result.code == 0) {
        onSuccess?.call(result.data);
      } else {
        _onError(result.code, result.message ?? "", url, onError);
      }
    }, onError: (dynamic e) {
      _cancelLogPrint(e, url);
      final NetError error = ExceptionHandle.handleException(e);
      _onError(error.code, error.msg, url, onError);
    });
  }

  /// 统一处理(onSuccess返回T对象，onSuccessList返回 List<T>)
  void asyncRequestNetwork<T>(
    Method method,
    String url, {
    BASE_URL? urlType,
    NetSuccessCallback<T?>? onSuccess,
    NetErrorCallback? onError,
    Object? params,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    Options? options,
  }) {
    Stream.fromFuture(_request<T>(
      method.value,
      url,
      baseUrlType: urlType,
      data: params,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
    )).asBroadcastStream().listen((result) {
      if (result.code == 0) {
        if (onSuccess != null) {
          onSuccess(result.data);
        }
      } else {
        _onError(result.code, result.message ?? "", url, onError);
      }
    }, onError: (dynamic e) {
      _cancelLogPrint(e, url);
      final NetError error = ExceptionHandle.handleException(e);
      _onError(error.code, error.msg, url, onError);
    });
  }

  void _cancelLogPrint(dynamic e, String url) {
    if (e is DioError && CancelToken.isCancel(e)) {
      MyLog.e('取消请求接口： $url');
    }
  }

  void _onError(int? code, String msg, String url, NetErrorCallback? onError) {
    if (code == null) {
      code = ExceptionHandle.unknown_error;
      msg = '未知异常';
    }
    MyLog.e('接口请求异常： code: $code, mag: $msg ,URL->$url');
    onError?.call(code.toString(), msg);
  }
}

Map<String, dynamic> parseData(String data) {
  return json.decode(data) as Map<String, dynamic>;
}

enum Method { get, post, put, patch, delete, head }

/// 域名类型
enum BASE_URL { base, m, m2 }

/// 使用拓展枚举替代 switch判断取值
/// https://zhuanlan.zhihu.com/p/98545689
extension MethodExtension on Method {
  String get value => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD'][index];
}
